/*
 * This is the main part of serial port operation. Including
 * putchar, getchar, readline function, and auto-completion
 * was supported.
 * printf is reserved and will be supported later.
 */

#include <string.h>

#include "global.h"
#include "serial.h"
#include "command.h"

// UART0 initialize
// desired baud rate: 9600
// actual: baud rate:9615 (0.2%)
// char size: 8 bit
// parity: Disabled
// stop bits: 1

extern cmd_type cmd_list[];

void uart0_init(void)
{
    UCSR0B = 0x00; //disable while setting baud rate
    UCSR0A = 0x00;
    UCSR0C = 0x06;
    UBRR0L = 0x31; //set baud rate lo
    UBRR0H = 0x00; //set baud rate hi
    UCSR0B = 0x18;
}

void put_char(char c)
{
    while(!(UCSR0A&(1<<UDRE0)));
    UDR0 = c;
}

char get_char()
{
    while(!(UCSR0A&(1<<RXC0)));
    return UDR0;
}

// print the string *s.
void print(char *s)
{
    char *p = s;
    while(*p) put_char(*p++);
    /*
      put_char('\r');
      put_char('\n');
    */
}

// return if readline successfully, use TAB for the autocompletion of commands.
void readline(char *s)
{
    char temp[50] = "";
    uint8 i, k, tmplen = 0, cmdlen = 0, pos = 0;
    char *p = s;
    uint8 cnt = 0;
    do{
        char c = get_char();
        if(c == '\b'){
            if(cnt != 0){
                put_char(c); put_char(' '); put_char(c);
                cnt--;
                tmplen--;
            }
        }
        else if(c == '\n' || c == '\r'){
            cnt = tmplen;
            strncpy(s, temp, cnt);
            s[cnt+1] = '\0';
            print("\r\n");
            return;
        }
        else if(c == '\t'){
            if(cnt != 0){
                for(i = pos; cmd_list[i].cmd[0] != 0; i++) cmdlen++;
                for(i = pos; ; i++){
                    if(cmd_list[i].cmd[0] == 0) {pos = 0; break;}
                    if(strncmp(p, cmd_list[i].cmd, cnt) == 0){
                        for(k = 0; k < tmplen; k++) {
                            put_char('\b');
                            put_char(' ');
                            put_char('\b');
                        }
                        print(cmd_list[i].cmd);
                        tmplen = strlen(cmd_list[i].cmd);
                        strcpy(temp, cmd_list[i].cmd);
                        pos = (i+1)%cmdlen;
                        break;
                    }
                }
            }
        }
        else{
            p[cnt++] = c;
            temp[tmplen++] = c;
            put_char(c);
        }
        if(c != '\t'){
            cnt = tmplen;
            memcpy(s, temp, sizeof(temp));
        }
    }while(1);
}

//reserve
void printf(const char *fmt, ...)
{
    return;
}
